package com.mxpio.erp.plan.controller;

import cn.hutool.core.collection.CollectionUtil;
import com.mxpio.erp.common.enums.OrderEnums;
import com.mxpio.erp.common.enums.OrderStatusEnums;
import com.mxpio.erp.common.jpa.model.OrderLine;
import com.mxpio.erp.common.order.service.OrderLineService;
import com.mxpio.erp.common.plan.entity.*;
import com.mxpio.erp.common.plan.service.OrganizationDemandLineService;
import com.mxpio.erp.common.sales.entity.SalesOrderLine;
import com.mxpio.erp.common.technology.entity.*;
import com.mxpio.erp.common.technology.vo.ItemWithSubExtendsVO;
import com.mxpio.erp.common.vo.NoticeClassVo;
import com.mxpioframework.common.util.BeanReflectionUtils;
import com.mxpioframework.common.vo.Result;
import com.mxpioframework.jpa.JpaUtil;
import com.mxpioframework.jpa.query.Criteria;
import com.mxpioframework.jpa.query.Operator;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Tag(name = "OrganizationDemandLineController", description = "组织需求行接口")
@RestController
@RequestMapping("/erp/plan/odline/")
public class OrganizationDemandLineController {

	@Autowired
	private OrganizationDemandLineService organizationDemandLineService;
	@Autowired
	private OrderLineService orderLineService;
	@GetMapping("list/{bizNo}")
	@Operation(summary = "组织需求行列表", description = "获取组织需求行列表（无分页）", method = "GET")
	public Result<List<OrganizationDemandLine>> list(@Parameter(description = "查询参数") Criteria criteria,
			@PathVariable(name = "bizNo") String bizNo)
			throws UnsupportedEncodingException {
		criteria.addCriterion("bizNo", Operator.EQ, bizNo);
		List<OrganizationDemandLine> organizationDemandLine = organizationDemandLineService.list(OrganizationDemandLine.class, criteria);
		return Result.OK(organizationDemandLine);
	}
	
	@GetMapping("page")
	@Transactional
	@Operation(summary = "组织需求行列表", description = "获取组织需求行列表（分页）", method = "GET")
	public Result<Page<OrganizationDemandLine>> page(@Parameter(description = "查询参数") Criteria criteria,
			@Parameter(description = "每页条数") Integer pageSize, @Parameter(description = "页号") Integer pageNo)
			throws UnsupportedEncodingException {
		Pageable page = PageRequest.of(pageNo - 1, pageSize);
		Page<OrganizationDemandLine> organizationDemandLine = organizationDemandLineService.listPage( page, criteria);

		List<OrganizationDemandLine> contents = organizationDemandLine.getContent();
		if(contents.size()>0){
			NoticeClassVo oDReceivingNoticeClazz = new NoticeClassVo(ODReceivingNotice.class, ODReceivingNoticeLine.class);
			NoticeClassVo oDRejectNotice = new NoticeClassVo(ODRejectNotice.class, ODRejectNoticeLine.class);
			NoticeClassVo oDSupplementNotice = new NoticeClassVo(ODSupplementNotice.class, ODSupplementNoticeLine.class);
			NoticeClassVo oDDefectiveRejNotice = new NoticeClassVo(ODDefectiveRejNotice.class, ODDefectiveRejNoticeLine.class);
			List<NoticeClassVo> noticeClassVos = new ArrayList<>();
			noticeClassVos.add(oDReceivingNoticeClazz);
			noticeClassVos.add(oDRejectNotice);
			noticeClassVos.add(oDSupplementNotice);//退料时考虑补料部分
			noticeClassVos.add(oDDefectiveRejNotice);
			orderLineService.handleBizOrderLineQuantity(contents, noticeClassVos, OrderEnums.AccessType.OUT.getCode());


			List<String> itemCodes = contents.stream().map(OrganizationDemandLine::getItemCode).collect(Collectors.toList());

			List<Item> items =  JpaUtil.linq(Item.class).in("itemCode", itemCodes).list();
			Map<String, Item> itemMap = JpaUtil.index(items,"itemCode");

			List<ItemLeadTimeProp> leadTimeProps =  JpaUtil.linq(ItemLeadTimeProp.class).equal("propType", "item").in("code", itemCodes).list();
			Map<String, ItemLeadTimeProp> leadTimePropMap = JpaUtil.index(leadTimeProps,"code");

			List<ItemPlanProp> planProps =  JpaUtil.linq(ItemPlanProp.class).equal("propType", "item").in("code", itemCodes).list();
			Map<String, ItemPlanProp> planPropMap = JpaUtil.index(planProps,"code");

			List<ItemPurchaseProp> purchaseProps =  JpaUtil.linq(ItemPurchaseProp.class).equal("propType", "item").in("code", itemCodes).list();
			Map<String, ItemPurchaseProp> purchasePropMap = JpaUtil.index(purchaseProps,"code");

			List<ItemStoreProp> storeProps =  JpaUtil.linq(ItemStoreProp.class).equal("propType", "item").in("code", itemCodes).list();
			Map<String, ItemStoreProp> storePropMap = JpaUtil.index(storeProps,"code");

			List<ItemMaterialProp> materialProps =  JpaUtil.linq(ItemMaterialProp.class).equal("propType", "item").in("code", itemCodes).list();
			Map<String, ItemMaterialProp> materialPropMap = JpaUtil.index(materialProps,"code");
			for (OrganizationDemandLine orderLine:contents){
				String itemCode = orderLine.getItemCode();

				Item item = itemMap.get(itemCode);
				if (item!=null){
					ItemWithSubExtendsVO extendsVO = new ItemWithSubExtendsVO();
					BeanReflectionUtils.copyProperties(extendsVO, item);
					extendsVO.setItemLeadTimeProp(leadTimePropMap.get(itemCode));
					extendsVO.setItemPlanProp(planPropMap.get(itemCode));
					extendsVO.setItemPurchaseProp(purchasePropMap.get(itemCode));
					extendsVO.setItemStoreProp(storePropMap.get(itemCode));
					extendsVO.setItemMaterialProp(materialPropMap.get(itemCode));
					orderLine.setItem(extendsVO);
				}
			}
		}
		return Result.OK(organizationDemandLine);
	}

	@GetMapping("page_twice/{zeroFlag}")
	@Transactional
	@Operation(summary = "组织需求行列表,带过滤最大可发货数量大于零", description = "获取组织需求行列表（分页）,带过滤最大可发货数量大于零", method = "GET")
	public Result<Page<OrganizationDemandLine>> page(@Parameter(description="是否过滤最大可发货数量大于零：1是，0否") @PathVariable(name = "zeroFlag", required = true) String zeroFlag,
													 @Parameter(description = "查询参数") Criteria criteria,
													 @Parameter(description = "每页条数") Integer pageSize, @Parameter(description = "页号") Integer pageNo) {
		if ("1".equals(zeroFlag)){
			Pageable page = PageRequest.of(pageNo - 1, pageSize);
			List<OrganizationDemandLine> contents = organizationDemandLineService.listAll(criteria);

			if(CollectionUtil.isNotEmpty(contents)){
				NoticeClassVo oDReceivingNoticeClazz = new NoticeClassVo(ODReceivingNotice.class, ODReceivingNoticeLine.class);
				NoticeClassVo oDRejectNotice = new NoticeClassVo(ODRejectNotice.class, ODRejectNoticeLine.class);
				NoticeClassVo oDSupplementNotice = new NoticeClassVo(ODSupplementNotice.class, ODSupplementNoticeLine.class);
				NoticeClassVo oDDefectiveRejNotice = new NoticeClassVo(ODDefectiveRejNotice.class, ODDefectiveRejNoticeLine.class);
				List<NoticeClassVo> noticeClassVos = new ArrayList<>();
				noticeClassVos.add(oDReceivingNoticeClazz);
				noticeClassVos.add(oDRejectNotice);
				noticeClassVos.add(oDSupplementNotice);//退料时考虑补料部分
				noticeClassVos.add(oDDefectiveRejNotice);
				orderLineService.handleBizOrderLineQuantity(contents, noticeClassVos, OrderEnums.AccessType.OUT.getCode());

				Iterator<OrganizationDemandLine> iterator = contents.iterator();
				while(iterator.hasNext()){
					OrganizationDemandLine next = iterator.next();
					BigDecimal actualMaxQuantity = next.getQuantity().subtract(next.getActualQuantity()).subtract(next.getPlanQuantity()).add(next.getActualRejectQuantity());
					if (actualMaxQuantity.compareTo(BigDecimal.ZERO)<=0){//移除不满足条件的，考虑小于零的情况，有可能补料超领，这部分也需要剔除
						iterator.remove();
					}
				}
				if (contents.size()>0){
					// 计算起始索引（从0开始）
					int startIndex = (pageNo - 1) * pageSize;
					if (startIndex < contents.size()) {
						// 获取当前页的数据子列表
						List<OrganizationDemandLine> pageList = contents.subList(startIndex, Math.min(startIndex + pageSize, contents.size()));

						List<String> itemCodes = pageList.stream().map(OrganizationDemandLine::getItemCode).collect(Collectors.toList());

						List<Item> items =  JpaUtil.linq(Item.class).in("itemCode", itemCodes).list();
						Map<String, Item> itemMap = JpaUtil.index(items,"itemCode");

						List<ItemLeadTimeProp> leadTimeProps =  JpaUtil.linq(ItemLeadTimeProp.class).equal("propType", "item").in("code", itemCodes).list();
						Map<String, ItemLeadTimeProp> leadTimePropMap = JpaUtil.index(leadTimeProps,"code");

						List<ItemPlanProp> planProps =  JpaUtil.linq(ItemPlanProp.class).equal("propType", "item").in("code", itemCodes).list();
						Map<String, ItemPlanProp> planPropMap = JpaUtil.index(planProps,"code");

						List<ItemPurchaseProp> purchaseProps =  JpaUtil.linq(ItemPurchaseProp.class).equal("propType", "item").in("code", itemCodes).list();
						Map<String, ItemPurchaseProp> purchasePropMap = JpaUtil.index(purchaseProps,"code");

						List<ItemStoreProp> storeProps =  JpaUtil.linq(ItemStoreProp.class).equal("propType", "item").in("code", itemCodes).list();
						Map<String, ItemStoreProp> storePropMap = JpaUtil.index(storeProps,"code");

						List<ItemMaterialProp> materialProps =  JpaUtil.linq(ItemMaterialProp.class).equal("propType", "item").in("code", itemCodes).list();
						Map<String, ItemMaterialProp> materialPropMap = JpaUtil.index(materialProps,"code");
						for (OrganizationDemandLine orderLine:pageList){
							String itemCode = orderLine.getItemCode();

							Item item = itemMap.get(itemCode);
							if (item!=null){
								ItemWithSubExtendsVO extendsVO = new ItemWithSubExtendsVO();
								BeanReflectionUtils.copyProperties(extendsVO, item);
								extendsVO.setItemLeadTimeProp(leadTimePropMap.get(itemCode));
								extendsVO.setItemPlanProp(planPropMap.get(itemCode));
								extendsVO.setItemPurchaseProp(purchasePropMap.get(itemCode));
								extendsVO.setItemStoreProp(storePropMap.get(itemCode));
								extendsVO.setItemMaterialProp(materialPropMap.get(itemCode));
								orderLine.setItem(extendsVO);
							}
						}
						return Result.OK(new PageImpl<>(pageList,page,contents.size()));
					}
				}
			}
			return Result.OK(new PageImpl<>(new ArrayList<>(),page,0));
		}else{
			Pageable page = PageRequest.of(pageNo - 1, pageSize);
			Page<OrganizationDemandLine> organizationDemandLine = organizationDemandLineService.listPage( page, criteria);

			List<OrganizationDemandLine> contents = organizationDemandLine.getContent();
			if(contents.size()>0){
				NoticeClassVo oDReceivingNoticeClazz = new NoticeClassVo(ODReceivingNotice.class, ODReceivingNoticeLine.class);
				NoticeClassVo oDRejectNotice = new NoticeClassVo(ODRejectNotice.class, ODRejectNoticeLine.class);
				NoticeClassVo oDSupplementNotice = new NoticeClassVo(ODSupplementNotice.class, ODSupplementNoticeLine.class);
				NoticeClassVo oDDefectiveRejNotice = new NoticeClassVo(ODDefectiveRejNotice.class, ODDefectiveRejNoticeLine.class);
				List<NoticeClassVo> noticeClassVos = new ArrayList<>();
				noticeClassVos.add(oDReceivingNoticeClazz);
				noticeClassVos.add(oDRejectNotice);
				noticeClassVos.add(oDSupplementNotice);//退料时考虑补料部分
				noticeClassVos.add(oDDefectiveRejNotice);
				orderLineService.handleBizOrderLineQuantity(contents, noticeClassVos, OrderEnums.AccessType.OUT.getCode());


				List<String> itemCodes = contents.stream().map(OrganizationDemandLine::getItemCode).collect(Collectors.toList());

				List<Item> items =  JpaUtil.linq(Item.class).in("itemCode", itemCodes).list();
				Map<String, Item> itemMap = JpaUtil.index(items,"itemCode");

				List<ItemLeadTimeProp> leadTimeProps =  JpaUtil.linq(ItemLeadTimeProp.class).equal("propType", "item").in("code", itemCodes).list();
				Map<String, ItemLeadTimeProp> leadTimePropMap = JpaUtil.index(leadTimeProps,"code");

				List<ItemPlanProp> planProps =  JpaUtil.linq(ItemPlanProp.class).equal("propType", "item").in("code", itemCodes).list();
				Map<String, ItemPlanProp> planPropMap = JpaUtil.index(planProps,"code");

				List<ItemPurchaseProp> purchaseProps =  JpaUtil.linq(ItemPurchaseProp.class).equal("propType", "item").in("code", itemCodes).list();
				Map<String, ItemPurchaseProp> purchasePropMap = JpaUtil.index(purchaseProps,"code");

				List<ItemStoreProp> storeProps =  JpaUtil.linq(ItemStoreProp.class).equal("propType", "item").in("code", itemCodes).list();
				Map<String, ItemStoreProp> storePropMap = JpaUtil.index(storeProps,"code");

				List<ItemMaterialProp> materialProps =  JpaUtil.linq(ItemMaterialProp.class).equal("propType", "item").in("code", itemCodes).list();
				Map<String, ItemMaterialProp> materialPropMap = JpaUtil.index(materialProps,"code");
				for (OrganizationDemandLine orderLine:contents){
					String itemCode = orderLine.getItemCode();

					Item item = itemMap.get(itemCode);
					if (item!=null){
						ItemWithSubExtendsVO extendsVO = new ItemWithSubExtendsVO();
						BeanReflectionUtils.copyProperties(extendsVO, item);
						extendsVO.setItemLeadTimeProp(leadTimePropMap.get(itemCode));
						extendsVO.setItemPlanProp(planPropMap.get(itemCode));
						extendsVO.setItemPurchaseProp(purchasePropMap.get(itemCode));
						extendsVO.setItemStoreProp(storePropMap.get(itemCode));
						extendsVO.setItemMaterialProp(materialPropMap.get(itemCode));
						orderLine.setItem(extendsVO);
					}
				}
			}
			return Result.OK(organizationDemandLine);
		}
	}

	@RequestMapping("save")
	@Operation(summary = "保存组织需求行", description = "保存组织需求行")
	public Result<List<OrganizationDemandLine>> save(@RequestBody List<OrganizationDemandLine> organizationDemandLines) {
		organizationDemandLineService.save(organizationDemandLines);
		return Result.OK(organizationDemandLines);
	}

	@PutMapping("open/{ids}")
	@Operation(summary = "打开组织需求行", description = "打开销售订单行,多个id用英文逗号分隔,bizNo和lineNo间使用英文冒号分隔,bizNo在前,lineNo在后", method = "PUT")
	public Result<? extends OrderLine> open(@PathVariable(name = "ids", required = true) String ids) {
		return orderLineService.updateCloseStatus(OrganizationDemandLine.class, ids, OrderStatusEnums.CloseStatus.OPEN);
	}

	@PutMapping("close/{ids}")
	@Operation(summary = "关闭组织需求行", description = "关闭组织需求行", method = "PUT")
	public Result<? extends OrderLine> close(@Parameter(description="业务单号，多个id用英文逗号分隔,bizNo和lineNo间使用英文冒号分隔,bizNo在前,lineNo在后") @PathVariable(name = "ids", required = true) String ids) {
		return orderLineService.updateCloseStatus(OrganizationDemandLine.class, ids, OrderStatusEnums.CloseStatus.CLOSED);
	}
}
